package br.com.zumbits.avd.web.client;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Iterator;
import javax.servlet.http.HttpServlet;

/**
 *
 * @author zumbits
 */
public class Conn extends HttpServlet {

    public static final String SERVER_URL = "http://lia.ufc.br:8080/server/server";
    //
    public static final String LOGIN_SUCCESS = "0";
    public static final String LOGIN_FAILURE = "1";
    public static final String LOGIN_ALREADY = "2";
    public static final String LOGIN_ERROR = "3";
    //
    public static final String MKDIR_SUCCESS = "0";
    public static final String MKDIR_NOT_LOGGED_IN = "1";
    public static final String MKDIR_NOT_FAILURE = "2";
    //
    public static final String UPLOAD_SUCCESS = "0";
    public static final String UPLOAD_NOT_LOGGED_IN = "1";
    public static final String UPLOAD_CONFLICT = "2";
    public static final String UPLOAD_FAILURE = "3";
    //
    public static final String DELETE_SUCCESS = "0";
    public static final String DELETE_NOT_LOGGED_IN = "1";
    public static final String DELETE_INVALID = "2";
    public static final String DELETE_ERROR = "3";
    //
    public static final String LOGOFF_SUCCESS = "0";
    public static final String LOGOFF_NOT_LOGGED_IN = "1";
    //
    public static final String LIST_NOT_LOGGED_IN = "1";
    //
    public static final String MSG_NOT_LOGGED_IN = "Você não está logado no sistema.";
    public static final String MSG_FAILURE = "Falha na conexão com o servidor";
    //
    public static final String UPLOAD_TEMP_FILENAME = "TEMPFILE";
    //
    private URL url;
    private URLConnection urlConnection;
    private boolean connected;

    public Conn(String urladdr) {
        /*
         * metodo construtor da classe, chamada no momento da autenticacao
         * (login)
         */

        try {
            url = new URL(SERVER_URL);
            connected = true;
        } catch (Exception e) {
            connected = false;
            e.printStackTrace();
        }

    }

    public boolean isConnected() {
        return connected;
    }

    public Login login(String username, String password) {
        /*
         * Faz um request ao servidor remoto e deserializa a resposta, mapeando
         * em um objeto da classe DVAnswerLogin
         */

        XStream xstream = new XStream(new DomDriver());
        xstream.alias("answerLogin", br.com.zumbits.avd.web.client.Login.class);
        Login login = null;
        try {
            login = (Login) xstream.fromXML(requestLogin(username, password));
        } catch (Exception ex) {
            //return ex.getMessage();
        }

        return login;
    }

    public String createFolder(String session_id, String path, String name) {
        /*
         * Faz um request ao servidor remoto e deserializa a resposta, mapeando
         * em um objeto da classe DVAnswerMkdir
         */

        XStream xstream = new XStream(new DomDriver());
        xstream.alias("answerCreateFolder", br.com.zumbits.avd.web.client.CreateFolder.class);
        CreateFolder createFolder;
        try {
            createFolder = (CreateFolder) xstream.fromXML(requestCreateFolder(session_id, path, name));
            return createFolder.getStatus();
        } catch (Exception ex) {
            return ex.getMessage();
        }
    }

    public Delete delete(String session_id, String path, String name) {
        /*
         * Faz um request ao servidor remoto e deserializa a resposta, mapeando
         * em um objeto da classe DVAnswerDelete
         */
        XStream xstream = new XStream(new DomDriver());
        xstream.alias("answerDelete", br.com.zumbits.avd.web.client.Delete.class);
        Delete delete = null;
        try {
            delete = (Delete) xstream.fromXML(requestDelete(session_id, path, name));
        } catch (Exception ex) {
        }

        return delete;
    }

    public Logoff logoff(String session_id, String nameuser) {
        /*
         * Faz um request ao servidor remoto e deserializa a resposta, mapeando
         * em um objeto da classe DVAnswerLogoff
         */
        XStream xstream = new XStream(new DomDriver());
        xstream.alias("answerLogoff", br.com.zumbits.avd.web.client.Logoff.class);
        Logoff logoff = null;

        try {
            logoff = (Logoff) xstream.fromXML(requestLogoff(session_id, nameuser));
            //System.out.println("RESPOSTA LOGOFF\n" + xstream.toXML(logoff));
        } catch (Exception ex) {
            //nothing here
        }

        return logoff;
    }

    /*
     * Faz um request ao servidor remoto e retorna ao usuario o stream de
     * bytes que o servidor retorna.
     */
    public InputStream download(String session_id, String path, String name) {
        XStream xstream = new XStream(new DomDriver());
        xstream.alias("answerDownload", br.com.zumbits.avd.web.client.Download.class);
        InputStream inputStream = null;

        try {
            Download download = (Download) xstream.fromXML(requestDownload(session_id, path, name));

            byte[] bytes = Base64.decode(download.getData(), Base64.URL_SAFE);

            inputStream = new ByteArrayInputStream(bytes);
        } catch (Exception e) {
            //
        }

        return inputStream;
    }

    public String upload(String session_id, String path, String name, String version, String local) {
        String encodeFile;
        byte b[];
        try {
            File arquivo = new File(local);
            FileInputStream fs = new FileInputStream(arquivo);
            b = new byte[(int) arquivo.length()];

            fs.read(b);
            encodeFile = Base64.encodeBytes(b, Base64.URL_SAFE);
        } catch (IOException e) {
            e.printStackTrace();
            return "erro";
        }

        (new File(local)).delete();

        XStream xstream = new XStream(new DomDriver());
        xstream.alias("answerUpload", br.com.zumbits.avd.web.client.Upload.class);
        Upload upload;

        try {
            InputStream is = requestUpload(session_id, path, name, version, encodeFile);
            upload = (Upload) xstream.fromXML(is);
            return upload.getStatus();
        } catch (Exception ex) {
            ex.printStackTrace();
            return ex.getMessage();
        }
    }

    public String listTable(String session_id, String path) {
        /*
         * Faz um request ao servidor remoto e deserializa a resposta, mapeando
         * em um objeto da classe DVAnswerLogin, em seguida gera uma String em
         * forma de uma tag html <table>
         */
        XStream xstream = new XStream(new DomDriver());
        xstream.alias("answerList", br.com.zumbits.avd.web.client.List.class);
        xstream.alias("file", br.com.zumbits.avd.web.client.FileAVD.class);
        xstream.alias("folder", br.com.zumbits.avd.web.client.FolderAVD.class);
        xstream.addImplicitCollection(br.com.zumbits.avd.web.client.List.class, "file", br.com.zumbits.avd.web.client.FileAVD.class);
        xstream.addImplicitCollection(br.com.zumbits.avd.web.client.List.class, "folder", br.com.zumbits.avd.web.client.FolderAVD.class);
        List list = null;

        String retorno = "";

        try {
            path = path.replace("//", "/");

            list = (List) xstream.fromXML(requestList(session_id, path));
            if (list.getStatus().equals(LIST_NOT_LOGGED_IN)) {
                return MSG_NOT_LOGGED_IN;
            }
        } catch (Exception ex) {
            return ex.getMessage();
        }

        if (list.getFolder() == null) {
            retorno += "<tr><td/><td>(nenhuma subpasta)</td><td/></tr>";
        } else {
            for (Iterator<FolderAVD> i = list.getFolder().iterator(); i.hasNext();) {
                FolderAVD dvf = i.next();
                retorno += "<tr>";
                retorno += "<td width =\"10\"><img src=\"lib/jquerytreeview/images/folder.gif\"/></td><td>" + dvf.getName() + "</td><td><span title=\"Abrir\" style=\"cursor:pointer;\" onclick=\"openFolder('" + list.getPath() + "/" + dvf.getName() + "')\"><img src=\"icons/abrir.gif\"/></span><span title=\"Excluir\" style=\"cursor:pointer;\" onclick=\"deleteFile('" + list.getPath() + "', '" + dvf.getName() + "')\"><img src=\"icons/deletar.gif\"/></span></td>";
                retorno += "</tr>";
            }
        }

        if (list.getFile() == null) {
            retorno += "<tr><td/><td>(nenhum arquivo)</td><td/></tr>";
        } else {
            for (Iterator<FileAVD> i = list.getFile().iterator(); i.hasNext();) {
                FileAVD fileAVD = i.next();
                retorno += "<tr>";
                retorno += "<td><img src=\"lib/jquerytreeview/images/file.gif\"/></td><td>" + fileAVD.getName() + "</td><td><span title=\"Download\" style=\"cursor:pointer;\" onclick=\"downloadFile('" + list.getPath() + "','" + fileAVD.getName() + "')\"><img src=\"icons/download.gif\"/></span><span title=\"Excluir\" style=\"cursor:pointer;\" onclick=\"deleteFile('" + list.getPath() + "', '" + fileAVD.getName() + "')\"><img src=\"icons/deletar.gif\"/></span></td>";
                retorno += "</tr>";
            }
        }
        return retorno;
    }

    /*
     * Faz um request ao servidor remoto e deserializa a resposta, mapeando
     * em um objeto da classe DVAnswerLogin, em seguida gera uma String em
     * forma de uma tag html <ul>
     */
    public String listUl(String session_id, String path) {
        XStream xstream = new XStream(new DomDriver());
        xstream.alias("answerList", br.com.zumbits.avd.web.client.List.class);
        xstream.alias("file", br.com.zumbits.avd.web.client.FileAVD.class);
        xstream.alias("folder", br.com.zumbits.avd.web.client.FolderAVD.class);
        xstream.addImplicitCollection(br.com.zumbits.avd.web.client.List.class, "file", br.com.zumbits.avd.web.client.FileAVD.class);
        xstream.addImplicitCollection(br.com.zumbits.avd.web.client.List.class, "folder", br.com.zumbits.avd.web.client.FolderAVD.class);
        List list = null;

        try {
            path = path.replace("//", "/");

            list = (List) xstream.fromXML(requestList(session_id, path));

            if (list.getStatus().equals(LIST_NOT_LOGGED_IN)) {
                return MSG_NOT_LOGGED_IN;
            }
        } catch (Exception ex) {
            return ex.getMessage();
        }

        if (list.getFolder() == null) {
            return "";
        }

        String retorno = "<ul>";
        for (Iterator<FolderAVD> i = list.getFolder().iterator(); i.hasNext();) {
            FolderAVD dvf = i.next();
            retorno = retorno.concat("<li class=\"closed\"><span class=\"folder\" onclick=\"openFolder('" + list.getPath() + "/" + dvf.getName() + "')\">" + dvf.getName() + "</span>");
            retorno += listUl(session_id, list.getPath() + "/" + dvf.getName());
            retorno = retorno.concat("</li>");
        }

        retorno = retorno.concat("</ul>");
        return retorno;
    }

    /*
     * Envia uma requisicao post de login ao servidor, e retorna o stream de bytes enviado pelo servidor.
     */
    private InputStream requestLogin(String username, String password) throws UnsupportedEncodingException, IOException {
        urlConnection = url.openConnection();
        urlConnection.setDoOutput(true);
        urlConnection.setDoInput(true);

        String xml =
                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "\n" +
                "<askLogin>" + "\n" +
                "\t" + "<user>" + username + "</user>" + "\n" +
                "\t" + "<password>" + password + "</password>" + "\n" +
                "</askLogin>";

        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(urlConnection.getOutputStream());

        outputStreamWriter.write(xml);
        outputStreamWriter.flush();
        outputStreamWriter.close();

        return urlConnection.getInputStream();
    }

    /*
     * Envia uma requisicao post de logoff ao servidor, e retorna o stream de bytes enviado pelo servidor.
     */
    private InputStream requestLogoff(String session_id, String nameuser) throws UnsupportedEncodingException, IOException {
        urlConnection = url.openConnection();
        urlConnection.setDoOutput(true);
        urlConnection.setDoInput(true);

        String xml =
                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "\n" +
                "<askLogoff>" + "\n" +
                "\t" + "<session>" + session_id.trim() + "</session>" + "\n" +
                "\t" + "<name>" + nameuser.trim() + "</name>" + "\n" +
                "</askLogoff>";

        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(urlConnection.getOutputStream());

        outputStreamWriter.write(xml);
        outputStreamWriter.flush();
        outputStreamWriter.close();

        return urlConnection.getInputStream();
    }

    private InputStream requestList(String session_id, String path) throws UnsupportedEncodingException, IOException {
        /*
         * Envia uma requisicao post de list ao servidor, e retorna o stream de bytes enviado pelo servidor.
         */
        urlConnection = url.openConnection();
        urlConnection.setDoOutput(true);
        urlConnection.setDoInput(true);

        String xml =
                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "\n" +
                "<askList>" + "\n" +
                "\t" + "<session>" + session_id.trim() + "</session>" + "\n" +
                "\t" + "<path>" + path.trim() + "</path>" + "\n" +
                "</askList>";

        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(urlConnection.getOutputStream());

        outputStreamWriter.write(xml);
        outputStreamWriter.flush();
        outputStreamWriter.close();

        return urlConnection.getInputStream();
    }

    private InputStream requestDelete(String session_id, String path, String name) throws UnsupportedEncodingException, IOException {
        /*
         * Envia uma requisicao post de delete ao servidor, e retorna o stream de bytes enviado pelo servidor.
         */
        path = path.replaceFirst("//", "/");
        urlConnection = url.openConnection();
        urlConnection.setDoOutput(true);
        urlConnection.setDoInput(true);

        String xml =
                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "\n" +
                "<askDelete>" + "\n" +
                "\t" + "<session>" + session_id.trim() + "</session>" + "\n" +
                "\t" + "<path>" + path.trim() + "</path>" + "\n" +
                "\t" + "<name>" + name.trim() + "</name>" + "\n" +
                "</askDelete>";

        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(urlConnection.getOutputStream());

        outputStreamWriter.write(xml);
        outputStreamWriter.flush();
        outputStreamWriter.close();

        return urlConnection.getInputStream();
    }

    /*
     * Envia uma requisicao post de download ao servidor, e retorna o stream de bytes enviado pelo servidor.
     */
    private InputStream requestDownload(String session_id, String path, String name) throws UnsupportedEncodingException, IOException {
        urlConnection = url.openConnection();
        urlConnection.setDoOutput(true);
        urlConnection.setDoInput(true);

        String xml =
                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "\n" +
                "<askDownload>" + "\n" +
                "\t" + "<session>" + session_id + "</session>" + "\n" +
                "\t" + "<path>" + path + "</path>" + "\n" +
                "\t" + "<name>" + name + "</name>" + "\n" +
                "</askDownload>";

        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(urlConnection.getOutputStream());

        outputStreamWriter.write(xml);
        outputStreamWriter.flush();
        outputStreamWriter.close();

        return urlConnection.getInputStream();
    }

    /*
     * Envia uma requisicao post de criacao de diretorios (mkdir) ao servidor, e retorna o stream de bytes enviado pelo servidor.
     */
    private InputStream requestCreateFolder(String session_id, String path, String name) throws UnsupportedEncodingException, IOException {
        urlConnection = url.openConnection();
        urlConnection.setDoOutput(true);
        urlConnection.setDoInput(true);

        String xml =
                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "\n" +
                "<askCreateFolder>" + "\n" +
                "\t" + "<session>" + session_id.trim() + "</session>" + "\n" +
                "\t" + "<path>" + path.trim() + "</path>" + "\n" +
                "\t" + "<name>" + name.trim() + "</name>" + "\n" +
                "</askCreateFolder>";

        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(urlConnection.getOutputStream());

        outputStreamWriter.write(xml);
        outputStreamWriter.flush();
        outputStreamWriter.close();

        return urlConnection.getInputStream();
    }

    /*
     * Envia uma requisicao post de upload ao servidor, e retorna o stream de bytes enviado pelo servidor.
     */
    private InputStream requestUpload(String session_id, String path, String name, String version, String file) throws UnsupportedEncodingException, IOException {
        urlConnection = url.openConnection();
        urlConnection.setDoOutput(true);
        urlConnection.setDoInput(true);

        System.out.println(session_id);

        String xml =
                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "\n" +
                "<askUpload>" + "\n" +
                "\t" + "<session>" + session_id.trim() + "</session>" + "\n" +
                "\t" + "<path>" + path + "</path>" + "\n" +
                "\t" + "<name>" + name + "</name>" + "\n" +
                "\t" + "<data>" + file + "</data>" + "\n" +
                "\t" + "<version>" + version + "</version>" + "\n" +
                "</askUpload>";

        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(urlConnection.getOutputStream());

        outputStreamWriter.write(xml);
        outputStreamWriter.flush();
        outputStreamWriter.close();

        return urlConnection.getInputStream();
    }

    private InputStream requestMove(String oldPath, String oldName, String newPath, String newName) throws UnsupportedEncodingException, IOException {
        /*
         * Envia uma requisicao post de move ao servidor, e retorna o stream de bytes enviado pelo servidor.
         * Metodo nao usado
         */
        oldPath = oldPath.replaceFirst("//", "/");
        newPath = newPath.replaceFirst("//", "/");
        urlConnection = url.openConnection();
        urlConnection.setDoOutput(true);
        urlConnection.setDoInput(true);

        String data = URLEncoder.encode("todo", "UTF-8") + "=" + URLEncoder.encode("move", "UTF-8");
        data += "&" + URLEncoder.encode("oldPath", "UTF-8") + "=" + URLEncoder.encode(oldPath, "UTF-8");
        data += "&" + URLEncoder.encode("oldName", "UTF-8") + "=" + URLEncoder.encode(oldName, "UTF-8");
        data += "&" + URLEncoder.encode("newPath", "UTF-8") + "=" + URLEncoder.encode(newPath, "UTF-8");
        data += "&" + URLEncoder.encode("newName", "UTF-8") + "=" + URLEncoder.encode(newName, "UTF-8");

        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(urlConnection.getOutputStream());

        outputStreamWriter.write(data);
        outputStreamWriter.flush();
        outputStreamWriter.close();

        return urlConnection.getInputStream();
    }

    private InputStream requestVersion(String path, String name) throws UnsupportedEncodingException, IOException {
        /*
         * Envia uma requisicao post de login ao servidor, e retorna o stream de bytes enviado pelo servidor.
         */
        path = path.replaceFirst("//", "/");
        urlConnection = url.openConnection();
        urlConnection.setDoOutput(true);
        urlConnection.setDoInput(true);

        String data = URLEncoder.encode("todo", "UTF-8") + "=" + URLEncoder.encode("version", "UTF-8");
        data += "&" + URLEncoder.encode("path", "UTF-8") + "=" + URLEncoder.encode(path, "UTF-8");
        data += "&" + URLEncoder.encode("name", "UTF-8") + "=" + URLEncoder.encode(name, "UTF-8");

        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(urlConnection.getOutputStream());

        outputStreamWriter.write(data);
        outputStreamWriter.flush();
        outputStreamWriter.close();

        return urlConnection.getInputStream();
    }
}
